package com.hyt.it.ogt.kq.service.gov.arrange;

import com.google.common.collect.Maps;
import com.hyt.core.base.BaseEntity;
import com.hyt.core.util.UUIDUtils;
import com.hyt.it.ogt.kq.common.config.exception.KqException;
import com.hyt.it.ogt.kq.common.enums.ArrangeRuleEnum;
import com.hyt.it.ogt.kq.common.gov.constant.ArrangeParamCodeEnum;
import com.hyt.it.ogt.kq.common.gov.constant.ResponseCode;
import com.hyt.it.ogt.kq.common.gov.constant.StringCodeEnum;
import com.hyt.it.ogt.kq.common.gov.enums.ProctorArrangeParamEnum;
import com.hyt.it.ogt.kq.service.gov.arrange.model.Proctor;
import com.hyt.it.ogt.kq.service.gov.arrange.model.Room;
import com.hyt.it.ogt.kq.service.gov.mapper.ExaminerMapper;
import com.hyt.it.ogt.kq.service.gov.mapper.TimeRoomCandidateMapper;
import com.hyt.it.ogt.kq.service.gov.model.entity.Examiner;
import com.hyt.it.ogt.kq.service.gov.model.entity.Task;
import com.hyt.it.ogt.kq.service.gov.model.entity.TimeExaminer;
import com.hyt.it.ogt.kq.service.gov.model.entity.TimeRoomExaminer;
import com.hyt.it.ogt.kq.service.gov.model.param.proctor.AutoProctorParam;
import com.hyt.it.ogt.kq.service.gov.model.vo.examiner.TimeRoomParamVO;
import com.hyt.it.ogt.kq.service.gov.service.*;
import com.hyt.loginfo.service.IUaDeptService;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentLinkedDeque;

public abstract class ProctorArrangeAbstractService {
    @Resource
    protected ITaskService iTaskService;
    @Resource
    protected IUaDeptService iUaDeptService;
    @Resource
    protected ITimeRoomCandidateService iTimeRoomCandidateService;
    @Resource
    protected TimeRoomCandidateMapper timeRoomCandidateMapper;
    @Resource
    protected ExaminerMapper examinerMapper;
    @Resource
    protected ITimeRoomExaminerService iTimeRoomExaminerService;
    @Resource
    protected ITimeExaminerService iTimeExaminerService;
    @Resource
    protected IExaminerService iExaminerService;
    @Resource
    protected ITimeService iTimeService;
    @Resource
    protected ITimeRoomParamService iTimeRoomParamService;

    public abstract void arrange(AutoProctorParam param);

    protected void checkLock(AutoProctorParam param) {
        Task task = iTaskService.getById(param.getTaskId());
        if (!task.getDataLock()) {
            throw new KqException(ResponseCode.TASK_DATA_LOCK_FALSE.getCode(), "考生编排数据没有锁定，不允许操作此功能。");
        }

        if (task.getProctorDataLock()) {
            throw new KqException(ResponseCode.PROCTOR_DATA_LOCK_FALSE.getCode(), "监考员编排已锁定，不允许操作此功能。");
        }
        if(iTimeRoomExaminerService.lambdaQuery().eq(TimeRoomExaminer::getTaskId, param.getTaskId()).eq(BaseEntity::getDelFlag, false).count() > 0) {
            throw new KqException(ResponseCode.PROCTOR_ARRANGE_EXIST.getCode(), "已存在监考员编排数据，不允许操作此功能。");
        }
        Optional<TimeRoomParamVO> op = param.getTimeRoomParamVOList().stream().filter(item -> ProctorArrangeParamEnum.ROOM_PROCTOR_NUM.getCode().equals(item.getCode())).findFirst();
        int count = iExaminerService.lambdaQuery().eq(Examiner::getTaskId, param.getTaskId()).eq(BaseEntity::getDelFlag, false).count();
        if(count == 0) {
            throw new KqException(ResponseCode.PROCTOR_ARRANGE_NO_PERSON.getCode(), "没有监考员，请先添加监考员。");
        }
        if(count < Integer.valueOf(op.get().getValue())){
            throw new KqException(ResponseCode.PROCTOR_ARRANGE_NOT_ENOUGH.getCode(), "监考员数量不够，请添加足够数量的监考员。");
        }
    }

    protected void checkArrange(AutoProctorParam param) {
        List<TimeRoomParamVO> list = iTimeRoomParamService.getTaskTimeRoomParam(param.getTaskId());
        Map<String,String> paramMap = Maps.newHashMap();
        list.stream().forEach(timeRoomParam -> {
            paramMap.put(timeRoomParam.getCode(),timeRoomParam.getValue());
        });
        String arrangeRule = paramMap.get(StringCodeEnum.ARRANGE_PARAM_ARRANGE_RULE.getCode());
        String arrangeType = paramMap.get(StringCodeEnum.ARRANGE_PARAM_ARRANGE_TYPE.getCode());
        Optional<TimeRoomParamVO> optional = param.getTimeRoomParamVOList().stream().filter(item -> ProctorArrangeParamEnum.ARRANGE_RULE.getCode().equals(item.getCode())).findFirst();
        String proctorArrangeRule = String.valueOf(optional.get().getValue());
        if(String.valueOf(ArrangeParamCodeEnum.ARRANGE_ROOM_TYPE_VIRTUAL.getCode()).equals(arrangeType)){
            if(arrangeRule.equals(String.valueOf(ArrangeRuleEnum.DEPT.getCode()))
                    && proctorArrangeRule.equals(String.valueOf(ArrangeRuleEnum.SELF.getCode()))){
                throw new KqException(ResponseCode.PROCTOR_ARRANGE_TYPE_DEPT.getCode(), "该考生编排模式下，仅支持按机构编排或随机编排监考员");
            } else if(arrangeRule.equals(String.valueOf(ArrangeRuleEnum.SELF.getCode()))
                 && proctorArrangeRule.equals(String.valueOf(ArrangeRuleEnum.DEPT.getCode()))) {
                throw new KqException(ResponseCode.PROCTOR_ARRANGE_TYPE_SELF.getCode(), "该考生编排模式下，仅支持按自定义编排或随机编排监考员");
            } else if(arrangeRule.equals(String.valueOf(ArrangeRuleEnum.RANDOM.getCode()))
                    && !proctorArrangeRule.equals("2")) {
                throw new KqException(ResponseCode.PROCTOR_ARRANGE_TYPE_RANDOM.getCode(), "该考生编排模式下，仅支持随机编排监考员");
            }
        }

    }

    /**
     * 根据考场绑定监考一定数量的监考员
     * @param param
     * @param teacherNum
     * @param timeExaminerMap
     * @param timeRoomExaminerList
     * @param e
     * @param proctors
     */
    protected void buildData(AutoProctorParam param, int teacherNum, Map<String, TimeExaminer> timeExaminerMap,
                             List<TimeRoomExaminer> timeRoomExaminerList, Room e, ConcurrentLinkedDeque<Proctor> proctors) {
        // 每个考场需要绑定监考员数量，同一考场，多个批次，都安排同一的监考老师
        for (int i = 0; i < teacherNum; i++) {
            if (proctors.isEmpty()) {
                break;
            }
            // 获取一个监考老师
            Proctor pop = proctors.poll();
            String[] times = e.getTimeIdStr().split(",");

            // 同一个监考员绑定在一个考场下多个批次中
            for (String time : times) {
                String timeKey = e.getRoomId() + "_" + time + "_" + pop.getUserId();
                TimeExaminer timeExaminer = timeExaminerMap.get(timeKey);
                if (timeExaminer == null) {
                    timeExaminer = new TimeExaminer();
                    timeExaminer.setExaminerId(pop.getExaminerId()).setTimeId(time).setUserId(pop.getUserId()).setTaskId(param.getTaskId()).setId(UUIDUtils.randomUUID());
                    timeExaminerMap.put(timeKey, timeExaminer);
                }
                timeRoomExaminerList.add(TimeRoomExaminer.builder().timeExaminerId(timeExaminer.getId()).timeId(time)
                        .roomId(e.getRoomId()).userId(pop.getUserId()).taskId(param.getTaskId()).build());
            }
        }
    }

    /**
     * 获取机构参数第几级
     * @param param
     * @param proctorArrangeParamEnum
     * @return
     */
    protected int getLevel(AutoProctorParam param, ProctorArrangeParamEnum proctorArrangeParamEnum) {
        Optional<TimeRoomParamVO> officeOp = param.getTimeRoomParamVOList().stream().filter(item -> proctorArrangeParamEnum.getCode().equals(item.getCode())).findFirst();
        return Integer.valueOf(officeOp.get().getValue());
    }

    /**
     * 获取需要安排多少个监考员
     * @param param
     * @return
     */
    protected int getTeacherNum(AutoProctorParam param) {
        Optional<TimeRoomParamVO> teacherOp = param.getTimeRoomParamVOList().stream().filter(item -> ProctorArrangeParamEnum.ROOM_PROCTOR_NUM.getCode().equals(item.getCode())).findFirst();
        return Integer.valueOf(teacherOp.get().getValue());
    }
}
